# Copyright (C) Nicola Bizzoca   2006/2007  <hannibal_smith@users.sourceforge.net>
# Copyright (C) Simone Economo   2006/2007  <ekoes@users.sourceforge.net>
# 
#    This file is part of Absynth-FTP.
#
#    Absynth-FTP is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 3 of the License, or
#    (at your option) any later version.
#
#    Absynth-FTP is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

from twisted.protocols.ftp import FTPClientBasic, FTPClient, FTPFileListProtocol
from twisted.internet.protocol import ClientCreator
from twisted.internet import reactor, protocol, defer
from twisted.internet import threads
from lib import filesmime as mimetypes
import gobject, os

class _BufferingProtocol(protocol.Protocol, gobject.GObject):
    __gsignals__ = {
                    'dataReceived' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                                   (gobject.TYPE_PYOBJECT,)),
                                   }
    
    def __init__(self, data):
        gobject.GObject.__init__(self)
        self.received = 0
        self.part = 0
        self.data = data
        self.buffer = open(self.data['file'], "wb")
    
    def dataReceived(self, data):
        self.buffer.write(data)
        self.received +=  len(data)
        self.part += len(data)
        if self.part >= (int(self.data['size'])/200) or (int(self.data['size']) - self.received) < self.part:
            data1 = {'file' :  self.data['file'],
                     'received' : self.received,
                     'size' : self.data['size']}
            self.emit('dataReceived', data1)
            self.part = 0
        

class FTPClass(gobject.GObject):
    __gsignals__ = {
                    'connected' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                                   (gobject.TYPE_STRING,)),
                    'listed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                                   (gobject.TYPE_PYOBJECT,)),
                    'pwd' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                                (gobject.TYPE_STRING,)),
                    'newDownload' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                            (gobject.TYPE_PYOBJECT,)),
                    'newUpload' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                            (gobject.TYPE_PYOBJECT,)),
                    'dwProgress' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                            (gobject.TYPE_PYOBJECT,)),
                    'upProgress' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                            (gobject.TYPE_PYOBJECT,)),
                    'endDownload' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                            (gobject.TYPE_PYOBJECT,)),
                    'endUpload' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                            (gobject.TYPE_PYOBJECT,)),
                    'failDownload' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                            (gobject.TYPE_PYOBJECT,)),
                    'failUpload' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                            (gobject.TYPE_PYOBJECT,)),
                    }
 
    def __init__(self):
        gobject.GObject.__init__(self)
        self.__mimetype = (os.path.isfile('/usr/bin/gnome-session') \
                       and mimetypes.Gnome()) \
                       or mimetypes.notGnome(24)
        self.downloadSession = None
        self.uploadSession = None
        self.downloadCoda = []
 
    def setLogger(self, logger):
        self.log = logger
 
    """ Events """
 
    def connectionMade(self, client):
        self.log.write("Connected")
        self.emit('connected', 'ok')
        self.FTP = client
        self.pwd()
        self.getDirs()
 
    def connectionLost(self, error):
        print "Connessione persa:"
        print "\t", error
 
    def connectionFailed(self, error):
        print "Connessione non riuscita:"
        print "\t", error
        self.emit('connected', error)
 
    def successResponse(self, message):
        print "Operazione effettuata:"
        print "\t", message
 
    def failedResponse(self, message):
        print "Operazione non riuscita:"
        print "\t", message
 
    """ Some useful methods """
 
    def connectTo(self, hostname, username, password):
        self.hostname, self.username, self.password = hostname, username, password
        client = ClientCreator(reactor, FTPClient, username, password, 0)
        connection = client.connectTCP(hostname, 21)
        connection.addCallbacks(self.connectionMade, self.connectionFailed)
 
    def getDirs(self, *args):
        listProtocol = FTPFileListProtocol()
        list = self.FTP.list(".", listProtocol)
        list.addCallbacks(self.parse, self.failedResponse, callbackArgs=(listProtocol,))      
    def parse(self, list, protocol):
        print "part"
        showHidden = 1
        data = []
        print "Lettura lista remota:"
        for file in protocol.files:
            if showHidden == 0 and item[0] == ".": continue
            print "\t", "%s %s %s" % (file['filename'].ljust(20), str(file['size']).ljust(10), file['date'].replace("  "," ").ljust(20))
            
            data.append({
                         'filetype' : file['filetype'] == 'd' and 'directory' or 'file',
                         'mime' : file['filetype'] == 'd' \
                         and self.__mimetype.return_folder_mime() \
                         or self.__mimetype.return_mime(file['filename']),
                         'filename' : file['filename'], 
                         'size' : file['size'],
                         'date' : file['date']
                         })
            
        print "Totale: %d oggetti" % (len(protocol.files))
        self.currentDirs = protocol.files
        self.emit('listed', data)
    
    def pwd(self):
        self.FTP.getDirectory().addCallbacks(self.successPWD, self.failedResponse)
    def successPWD(self, message):
        self.emit('pwd', message)
        
    def cwd(self, path):
        print path
        if path == '..':
            self.FTP.cdup().addCallbacks(self.successCWD, self.failedResponse)
        else:
            self.FTP.cwd(path).addCallbacks(self.successCWD, self.failedResponse)
    def successCWD(self, message):
        self.pwd()
        self.getDirs()


    def checkCoda(self):
        del self.downloadCoda[0]
        print  self.downloadCoda
        if len(self.downloadCoda) > 0:
            self.directDownload(self.downloadCoda[0][0], self.downloadCoda[0][1], self.downloadCoda[0][2])
        else:
            print "no more download"
             
    def directDownload(self, fileDetail):
        proto = _BufferingProtocol(fileDetail)
        proto.connect('dataReceived', self.progress)
        print self.hostname
        cc = protocol.ClientCreator(reactor, FTPClient, self.username, self.password, passive=1)
        client = cc.connectTCP(self.hostname, 21).addCallbacks(self.__retrive, self.connectionFailed, callbackArgs=(proto, fileDetail))

    def __retrive(self, client, proto, fileDetail):
        self.downloadSession = client
        download = self.downloadSession.retrieveFile(fileDetail["path"] + '/' +  fileDetail["file"], proto)
        download.addCallbacks(self.successDOWNLOAD, self.failDOWNLOAD, callbackArgs=(fileDetail,))
        
    def download(self, file, size, path):
        fileDetail = {'file' : file, 'size' : size, 'path' : path}
        self.emit('newDownload', fileDetail)
        self.downloadCoda.append(fileDetail)
        if self.downloadSession == None:
            reactor.callInThread(self.directDownload, fileDetail)        

    def successDOWNLOAD(self, message, data):
        self.downloadSession.quit()
        self.dowloadSession = None
        self.checkCoda()
        self.emit('endDownload', data)
    def failDOWNLOAD(self, message):
        self.downloadSession.quit()
        self.dowloadSession = None
        print message
        self.checkCoda()
        self.emit('failDownload', message)
    def progress(self, id, data):
        progress = 100 * float(data['received'])/float(data['size'])
        data1 = {'progress' : progress,
                 'received' : data['received'],
                 'file' : data['file']}
        self.emit('dwProgress', data1)
        
    def quit(self):
        print self.FTP.popCommandQueue()
       # self.FTP.queueStringCommand('ABOR').addCallbacks(self.successResponse, self.failedResponse)
       
        self.FTP.quit().addCallbacks(self.successResponse, self.failedResponse)
        print self.FTP.popCommandQueue()